#include "../../core/pch.h"
#include "../utils/utils.c"
#include "../../pi/Process.h"
#include "../../pi/BinarySemaphore.h"

unsigned int N, p, times_count;
int ret;

/** Id identifying shared memory segment id. */
int segment_id;

/** Semaphore id which will be used to synchornize master processes. */
int sem_id;

/** Port on which to listen. */
int receiver_port;

/** Pointer for shared memory. */
struct info_table* shared_memory;

int main(int argc, char** argv)
{
	DEBUGS("receiver: running");

	FILE* outFile = fopen("out.txt", "w+");

	segment_id = atoi(argv[1]);
	sem_id = atoi(argv[2]);
	receiver_port = atoi(argv[3]);

	/** Attach the shared memory segment. */
	shared_memory = (struct info_table*) shmat(segment_id, NULL, 0);

	struct sockaddr_in receiver_addr; 
	memset(&receiver_addr, 0, sizeof(receiver_addr)); 
	receiver_addr.sin_family = AF_INET; 
	receiver_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
	receiver_addr.sin_port = htons(receiver_port); 

	int receiver_sock = socket(AF_INET, SOCK_STREAM, 0); 
	if (receiver_sock < 0)
	{
		DEBUGS("receiver: error creating listening socket");
		exit(1);
	}

	ret = bind(receiver_sock, (struct sockaddr*) &receiver_addr, sizeof(receiver_addr)); 
	if (ret < 0)
	{
		DEBUGS("receiver: bind error");
		exit(1);
	}

	ret = listen(receiver_sock, 64); 
	if (ret < 0)
	{
		DEBUGS("receiver: listen error");
		exit(1);
	}

	socklen_t len;
	while (true)
	{
		DEBUGS("receiver: waiting for results from slaves");

		struct sockaddr_in cliaddr;
		len = sizeof(struct sockaddr);
		int worker_sock = accept(receiver_sock, (struct sockaddr*) &cliaddr, &len);
		if (worker_sock < 0)
		{
			DEBUGS("receiver: error accepting connection to receiver");
			exit(1);
		}

		recv(worker_sock, &N, sizeof(unsigned int), 0);
		recv(worker_sock, &p, sizeof(unsigned int), 0);
		recv(worker_sock, &times_count, sizeof(unsigned int), 0);

		DEBUGS("receiver: accepted connection from slave, results for %u", N);

		if (Process::Create() == 0)
		{
			BinarySemaphore::Decrement(sem_id);
			while (times_count-- > 0)
				shared_memory->NUMBER = shared_memory->NUMBER / p;		
			BinarySemaphore::Increment(sem_id);
			return 0;
		}

		//DEBUGS("N = %d, p = %d, times_count = %d", N, p, times_count);
		fprintf(outFile, "N = %d, p = %d, times_count = %d\n", N, p, times_count); 
		fflush(outFile);

		close(worker_sock);

		if (shared_memory->NUMBER == 1)
		{
			fclose(outFile);
			exit(0);
		}
	}

	fclose(outFile);

	return 0;
}


